package com.autonavi.yunda.yunji.core.vo.node;

import com.autonavi.yunda.yunji.common.exception.AmapException;
import com.autonavi.yunda.yunji.common.exception.AmapExceptionCode;
import com.autonavi.yunda.yunji.common.exception.AmapPreconditions;
import com.autonavi.yunda.yunji.common.utils.JsonUtils;
import com.autonavi.yunda.yunji.core.enums.NodeType;
import com.autonavi.yunda.yunji.core.utils.ValidUtil;
import com.autonavi.yunda.yunji.core.vo.param.NodeParam;
import com.autonavi.yunda.yunji.core.vo.param.ParamValidator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;

import java.util.ArrayList;
import java.util.List;

import static com.autonavi.yunda.yunji.core.config.EngineConstant.GROOVY_SYNTAX_VARIABLE_REGEX;
import static com.autonavi.yunda.yunji.core.config.EngineConstant.INVALID_VAR_NAME_SET;

/**
 * @author cizhong.wcs
 * @date 2022/5/24 14:24
 */
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class BaseNode {
    /**
     * 节点类型
     */
    public NodeType nodeType;
    public String name;
    public String var;
    public String desc;
    public List<NodeParam> params = new ArrayList<>();
    /**
     * 操作人(debug使用,之后记录debug数据)
     */
    public String operator;
    public Long nodeTimeoutMillis;
    public List<ParamValidator> resultValidators = new ArrayList<>();
    /**
     * 零部件id
     */
    @Getter
    public String componentId;
    /**
     * 零部件类型
     */
    @Getter
    public String componentType;
    public Boolean singleNodeDebug = false;


    /**
     * 根据jsonNode中的nodeType属性，转为对应的BaseNode对象（策略模式）
     * @param jsonNode
     * @return
     */
    public static BaseNode parseNode(JsonNode jsonNode) {
        NodeType nodeType;
        try {
            nodeType = NodeType.valueOf(jsonNode.get("nodeType").asText());
        } catch (Exception e) {
            throw new AmapException(AmapExceptionCode.COMMON_ILLEGAL_PARAM, "nodeType:" + jsonNode.get("nodeType") + "解析异常 jsonNode :" + JsonUtils.toString(jsonNode), e);
        }
        BaseNode baseNode = JsonUtils.from(JsonUtils.toString(jsonNode), nodeType.getNodeClass());
        baseNode.completeFields();
        return baseNode;
    }

    /**
     * 继承节点自定义参数校验
     */
    protected void customParamCheck() {

    }

    public void checkParam() {
        AmapPreconditions.checkArgumentForUser(StringUtils.isNoneBlank(getName()), "节点名称不能为空");
        AmapPreconditions.checkArgumentForUser(!INVALID_VAR_NAME_SET.contains(getName()), "节点名" + getName() + "不能为系统关键字");
        AmapPreconditions.checkArgumentForUser(ValidUtil.checkRegexAndReturn(getName(), GROOVY_SYNTAX_VARIABLE_REGEX), "节点名" + getName() + "只能使用[字母,数字,_]且不能以数字开头");
        AmapPreconditions.checkArgumentForUser(StringUtils.isNoneBlank(getVar()), "节点" + getName() + "输出映射字段不能为空");
        AmapPreconditions.checkArgumentForUser(!INVALID_VAR_NAME_SET.contains(getVar()), "节点" + getName() + "输出映射字段不能为系统关键字");
        AmapPreconditions.checkArgumentForUser(ValidUtil.checkRegexAndReturn(getVar(), GROOVY_SYNTAX_VARIABLE_REGEX), "节点" + getName() + "只能使用[字母,数字,_]且不能以数字开头");
        params.forEach(param -> param.checkParam(getName()));
        AmapPreconditions.checkArgumentForUser(params.size() == params.stream().map(NodeParam::getName).distinct().count(), "节点" + getName() + "中参数名称不能重复");
        customParamCheck();
    }

    private void completeFields() {
        if (Strings.isBlank(var)) {
            var = name;
        }
    }
}
